﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Linq;
using NUnit.Framework;

//继承自editor不会被打包进包内
public class BuildTool:Editor
{
    [MenuItem("Tools/Build Windows Bundle")]
    //静态方法引用的成员必须是静态的
    static void BundleWindowsBuild()
    {
        Debug.Log("打包方法执行");
        Build(BuildTarget.StandaloneWindows);
    }
    [MenuItem("Tools/Build Android Bundle")]
    static void BundleAndroidBuild()
    {
        Build(BuildTarget.Android);
    }
    [MenuItem("Tools/Build iOS Bundle")]
    static void BundleIOSBuild()
    {
        Build(BuildTarget.iOS);
    }



    //为什么要用静态方法
    static void Build(BuildTarget buildTarget)
    {
        //AssetBundleBuild结构体列表，用于存储所有的AssetBundle构建信息
        List<AssetBundleBuild> assetBundleBuilds = new List<AssetBundleBuild>();
        //文件信息列表
        List<string> bundleInfos = new List<string>();
        //获取所有需要打包的资源文件，将文件路径存储到files数组中(注意这里的路径是绝对路径)
        //该方法获取的路径的拼接起来的，第一个参数+后面的路径，注意后面的路径是反斜杠，可能会出问题
        string[] files = Directory.GetFiles(PathUtil.BuildResourcesPath, "*", SearchOption.AllDirectories);
        //meta文件是Unity的资源文件的附属文件，不需要打包，所以需要过滤掉
        for (int i = 0; i < files.Length; i++)
        {
            if (files[i].EndsWith(".meta"))
                continue;
            //获取标准路径(没有空格和反斜杠)
            string filename = PathUtil.GetStandardPath(files[i]);

            Debug.Log("filename:" + filename);

            AssetBundleBuild assetBundle = new AssetBundleBuild();

            //结构体需要两个参数，一个是包名，一个是包含的资源文件路径(这里要求相对目录，是一个数组，可以包含很多文件)
            //把需要打包的每个文件的相对路径存储到assetBundle.assetNames中，
            string assetName = PathUtil.GetUnityPath(filename);
            Debug.Log("assetName: " + assetName);
            assetBundle.assetNames = new string[] { assetName };
            //把包名设置为相对于BuildResourcesPath的相对路径名，转为小写
            string bundleName = filename.Replace(PathUtil.BuildResourcesPath, "");
            //Debug.Log("bundleName: " + bundleName);
            assetBundle.assetBundleName = bundleName + ".ab";
            //放入list中
            assetBundleBuilds.Add(assetBundle);

            //寻找到所有依赖资源路径
            List<string> dependenciesInfo = GetDependencies(assetName);
            //将依赖资源路径存储到bundleInfo中(这里注意要加上.ab，名字和上面存储的包名后缀一致，否则在资源管理器读取依赖信息进行加载的时候会报错）
            string bundleInfo = assetName + "|" + bundleName + ".ab";
            if (dependenciesInfo.Count > 0)
            {
                bundleInfo = bundleInfo + "|" + string.Join("|", dependenciesInfo);
            }
            bundleInfos.Add(bundleInfo);
        }

        //判断打包时是否存在该文件夹，如果有，则删掉重新创建；如果没有，则创建。此逻辑不用else
        if (Directory.Exists(PathUtil.BundleOutPath))
        {
            Directory.Delete(PathUtil.BundleOutPath, true);//true代表是否递归删除所有文件
        }
        Directory.CreateDirectory(PathUtil.BundleOutPath);
        //进行打包，只能接受array，因此需要进行转换

        BuildPipeline.BuildAssetBundles(PathUtil.BundleOutPath, assetBundleBuilds.ToArray(), BuildAssetBundleOptions.None, buildTarget);
        Debug.Log("打包完成");
        File.WriteAllLines(PathUtil.BundleOutPath + "/" +AppConst.FileListName, bundleInfos.ToArray());
        Debug.Log("依赖文件信息写入完成");
        //资源更新后可能会出现未来得及在编辑器显示的情况， Unity 编辑器重新扫描和更新项目中的资源文件
        AssetDatabase.Refresh();
    }

    //获取依赖信息
    static List<string> GetDependencies(string curFile)
    {
        //获取依赖信息
        List<string> dependence = new List<string>();
        string[] files = AssetDatabase.GetDependencies(curFile);
        //过滤掉cs文件和当前文件
        dependence = files.Where(file => !file.EndsWith(".cs") && !file.EndsWith(curFile)).ToList();
        return dependence;
    }
}




